/*
 * File: ttds_cocore.h
 * Author: Liang YaoZhan <262666882@qq.com>
 * Brief:  co-routine implemnted through setjmp
 *
 * Copyright (c) 2022 - 2023 Liang YaoZhan <262666882@qq.com>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * History:
 * ================================================================
 * 2023-08-05 Liang YaoZhan <262666882@qq.com> created
 *
 */

#ifndef ttds_coTASK_H
#define ttds_coTASK_H

#include <stdint.h>
#include <setjmp.h>

#include "ttds/ttds_config.h"
#include "ttds/ttds_queue.h"
#include "ttds/ttds_timer.h"

#define ttds_coCPLUSPLUS_BEGIN \
    extern "C"                \
    {
#define ttds_coCPLUSPLUS_END }

#ifdef __cplusplus
ttds_coCPLUSPLUS_BEGIN
#endif

/************************************************** ttds_cothread_t ***************************************/
/************************************************** ttds_cothread_t ***************************************/

#ifndef ttds_assert
#define ttds_assert(c) do{ ;}while(0)
#endif

#define ttds_coWAITING 0
#define ttds_coYIELDED 1
#define ttds_coEXITED 2
#define ttds_coPAUSE 3
#define ttds_coENDED 4

typedef char ***base_reg_t;

typedef enum 
{
    ttds_coSTATE_INIT, /* */
    ttds_coSTATE_READY,
    ttds_coSTATE_PENDING,
    ttds_coSTATE_DEAD,
} ttds_costate_t;
typedef enum 
{
    ttds_coEOK,
    ttds_coEEMPTY,
    ttds_coETERMINATED,
    ttds_coETIMEOUT,
} ttds_coerr_t;

struct _ttds_threadpool;
typedef struct _ttds_threadpool ttds_threadpool_t;
typedef struct _ttds_thread
{
/* private: */
    int stack_size;
    ttds_queue_t node_state;
    ttds_queue_t node_pending_resource;
    ttds_timer_t timer;
    ttds_coerr_t err;
    ttds_costate_t state;
    jmp_buf jb;

/*public:*/
    const char *name;
    char *stack_low;
    char *stack_check;
    char *stack_high;
    int exit_code;
    int (*entry)(void *arg);
    void *arg;
} ttds_cothread_t;
#define ttds_coOBJECT(obj) ttds_cothread_t obj

struct _ttds_sem
{
    int count;
    ttds_queue_t head_pendings;
};
typedef struct _ttds_sem ttds_cosem_t;
struct _ttds_mutex
{
    ttds_cothread_t *p_owner;
    ttds_queue_t head_pendings;
    uint16_t recursive;
    uint8_t is_recursive;
};
typedef struct _ttds_mutex ttds_comutex_t;

struct _ttds_condition_variable
{
    ttds_cosem_t sem;
};
typedef struct _ttds_condition_variable ttds_condition_variable_t;

#ifndef DEF_MAIN_THREAD_OBJECT
#define DEF_MAIN_THREAD_OBJECT(x) ttds_cothread_t x
#endif

struct _ttds_threadpool
{
/* private: */
    ttds_cothread_t *p_thread_current;
    ttds_queue_t head_state_pending;
    ttds_queue_t head_state_running;
    ttds_tick_t ticker;
    int32_t systick;
    jmp_buf jb_create_thread_req;
    jmp_buf jb_create_thread_res;
    ttds_cothread_t *p_thread_to_init_stack;
    char *p_stack_start;
    char *p_stack_current;
    uint8_t enable_stack_check;
    uint8_t is_stack_going_down;

/*public:*/
    DEF_MAIN_THREAD_OBJECT(main);
};


#define ttds_cosem(sem) ttds_cosem_t sem

/* you should define this function before using ttds_coDELAY */
int32_t ttds_cothread_sys_tick_get_ms(void);

void ttds_cosem_init(ttds_cosem_t *p_this, int init_count);
ttds_coerr_t ttds_cosem_take(ttds_cosem_t *p_this, int delay_tick); /* delay_tick: -1 forevery */
void ttds_cosem_give(ttds_cosem_t *p_this, int count);
void ttds_cosem_give_all(ttds_cosem_t *p_this);
void ttds_cosem_destroy(ttds_cosem_t *p_this);

void ttds_comutex_init(ttds_comutex_t *p_this, int is_recursive);
ttds_coerr_t ttds_comutex_lock( ttds_comutex_t *p_this, int delay_tick ); /* delay_tick: -1 forevery */
void ttds_comutex_unlock( ttds_comutex_t *p_this );
void ttds_comutex_destroy( ttds_comutex_t *p_this );

void ttds_cothread_delay(int tick);
int ttds_cothread_get_stack_used(ttds_cothread_t *ptr );
void ttds_cothread_yeild(void);
ttds_cothread_t *ttds_cothread_self(void);

void ttds_threadpool_init(int main_thread_stack_size );
void ttds_threadpool_add_thread(ttds_cothread_t *p_threads, int count,int main_thread_stack_size );
int  ttds_threadpool_run( int (*func)(void *arg), void *arg, int thread_stack_size_need, const char *name );
ttds_threadpool_t *ttds_threadpool_default(void);
void ttds_threadpool_startup(void);
int  ttds_threadpool_stack_used(void);
void ttds_threadpool_timer_start(ttds_timer_t *p_timer, int ms);
void ttds_threadpool_timer_remove(ttds_timer_t *p_timer);
int ttds_idle_get_sleep_time(void);

#define ttds_condition_variable_init(pthis) ttds_cosem_init(&(pthis)->sem, 0)
#define ttds_condition_variable_destroy(pthis) ttds_cosem_destroy(&(pthis)->sem)
void ttds_condition_variable_wait( ttds_condition_variable_t *pthis, ttds_comutex_t *p_mutex);
ttds_coerr_t ttds_condition_variable_wait_for( ttds_condition_variable_t *p_this, ttds_comutex_t *p_mutex, int delay_ms);
#define ttds_condition_variable_notify_one(pthis) ttds_cosem_give(&(pthis)->sem, 1)
#define ttds_condition_variable_notify_all(pthis) ttds_cosem_give_all(&(pthis)->sem)

#ifdef __cplusplus
ttds_coCPLUSPLUS_END
#endif



#endif
